package org.hagopa.games.moneypool.policy;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;

public class FlashSocketPolicySupport implements Runnable{
	Selector sel = null;
	private ServerSocket srvSocket = null;
	private int port = 843;
	private static ServerSocketChannel ssc = null;
	private boolean isRunning = false;
	private File policyPath = null;
	private String policyRequest = "<policy-file-request/>";
	private boolean responded = false;
	
	public FlashSocketPolicySupport(String policypathStr){
		this.policyPath = new File(policypathStr);
		if(policyPath.exists() == false)
		{
			System.out.println("[FSP]:No policy File is exists!");
			return;
		}
		
	}
	public boolean init()
	{
		
		this.isRunning = true;
		
		
		new Thread( this ).start();
			return true;
	}
	public boolean readRequest(SocketChannel socketChannel) throws IOException
		{
		int bytes_no = 0;
		ByteBuffer dst =  ByteBuffer.allocate(128);
		if((bytes_no = socketChannel.read(dst)) == 0)
		{
			System.out.println("[FSP]:Nothing to read");
			return false;
		}
		else
		{
			System.out.println("bbb" + bytes_no);
			byte [] request = new byte[64];
			dst.rewind();
			
			dst.get(request, 0, 23);
			
			String requestStr = new String(request);
			System.out.println("[FSP]:Request : " + requestStr);
			if(requestStr.indexOf(policyRequest) != 0)
			{
				System.out.println("[FSP]:Not Valid Request");
				socketChannel.close();
				return false;
			}
		}
		return true;
	}
	private synchronized  SocketChannel accept(SelectionKey key) throws IOException {
		// For an accept to be pending the channel must be a server socket channel.
		
		ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
		System.out.println("[FSP]:\n=================\nAccept New Connection!!\n=================");
		
		
		// Accept the connection and make it non-blocking
		SocketChannel socketChannel = serverSocketChannel.accept();
		//Socket socket = socketChannel.socket();
		socketChannel.configureBlocking(false);
		InetAddress ipa = socketChannel.socket().getInetAddress();
		System.out.println("[FSP]:IPAddress : " + ipa.getHostName());
		if(readRequest(socketChannel) == true)
		{
			socketChannel.write(getPolicyFile());
			responded = true;
			return socketChannel;
		}
		
		
		socketChannel.register(this.sel, SelectionKey.OP_WRITE);
		socketChannel.register(this.sel, SelectionKey.OP_READ);
		
		return socketChannel;
	}
	
	private boolean startServer()
	{
		System.out.println("\n=================\n Starting Flash Policy Server Thread!!!!!\n=================\n");
		
		try {
			// Instead of creating a ServerSocket,
		      // create a ServerSocketChannel
			ssc = ServerSocketChannel.open();

		      // Set it to non-blocking, so we can use select
			ssc.configureBlocking( false );

		      // Get the Socket connected to this channel, and bind it
		      // to the listening port
		    srvSocket = ssc.socket();
		      
		    if(null == srvSocket)
			{
				System.out.println("[FSP]:Failed to create Server Socket");
				return false;
			}
		      
		    InetSocketAddress isa = new InetSocketAddress( port );
		    srvSocket.bind( isa );

			sel = Selector.open();
		
			ssc.register(sel, SelectionKey.OP_ACCEPT);
		}
		catch (ClosedChannelException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		} 
		
		
		return true;
	}
	

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public boolean isRunning() {
		return isRunning;
	}

	public void setRunning(boolean isRunning) {
		this.isRunning = isRunning;
	}

	public static ServerSocketChannel getSsc() {
		return ssc;
	}
	
	public void run() {
		if(startServer() == true)
		{
			System.out.println("[FSP]:\n-----------------\nStarted succesfully\n--------------------\n");
			while(isRunning)
			{
				int num = 0;
				try {
					num = sel.select();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				if(num == 0)
					continue;
				Set<SelectionKey> keys = Collections.synchronizedSet(sel.selectedKeys());
				
				Iterator<SelectionKey> it = keys.iterator();
					while(it.hasNext())
					{
				
					SelectionKey skey = (SelectionKey)it.next();
					it.remove();
						if(skey.isValid() && skey.isAcceptable())
						{
							try {
								accept(skey);
								if(responded == true)
									removeChannel(skey);
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							
						}
						else if (skey.isValid() && skey.isReadable())
						{
							
							System.out.println("[FSP]:\n-------\nReadable!!!");
							
							try {
								if(readRequest(((SocketChannel)skey.channel())) == true)
								{
									System.out.println("[FSP]:Before get Policy File");
									byte [] array = new byte[1];
									array[0] = 0;
									ByteBuffer tmp = getPolicyFile();
									ByteBuffer zeroend = ByteBuffer.wrap(array);
									if(tmp != null)
									{
										System.out.println("[FSP]:Very Good");
										((SocketChannel)skey.channel()).write(tmp);
										((SocketChannel)skey.channel()).write(zeroend);
									}
									
									System.out.println("[FSP]:Written policy file");
									
								}
								removeChannel(skey);
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							
						}
						
					}
				keys.clear();
				
			}
		}
	}
	
	
	private void removeChannel(SelectionKey key)
	{
		
		key.cancel();
		try {
			key.channel().close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	private ByteBuffer getPolicyFile()
	{
		ByteBuffer dst =  ByteBuffer.allocate(1024);
		FileChannel srcChannel = null;
		if(this.policyPath.canRead() == true)
		{
			
			try {
				System.out.println("Path : " + this.policyPath.getPath());
				srcChannel = new FileInputStream(this.policyPath.getPath()).getChannel();
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			try {
				srcChannel.read(dst);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("[FSP]:Position : " + dst.position());
		//dst.putInt(0);
		//System.out.println("[FSP]:Position : " + dst.position());
		
		dst.rewind();
		System.out.println("[FSP]:File in Byte Buffer");
		return dst;
	}
	
}
